package cn.aws360.boot.system.biz.service.impl;

import cn.aws360.boot.auth.api.LoginApi;
import cn.aws360.boot.auth.api.constant.AuthConstant;
import cn.aws360.boot.auth.api.exception.AuthExceptionEnum;
import cn.aws360.boot.auth.api.pojo.response.LoginUserModel;
import cn.aws360.boot.base.api.constant.BaseConstant;
import cn.aws360.boot.base.api.constant.enums.DelFlagEnum;
import cn.aws360.boot.base.api.exception.ServiceException;
import cn.aws360.boot.system.api.exception.SysExceptionEnum;
import cn.aws360.boot.system.biz.domain.*;
import cn.aws360.boot.system.biz.helper.TreeHelper;
import cn.aws360.boot.system.biz.service.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static cn.aws360.boot.auth.api.constant.AuthConstant.CACHE_CAPTCHA_CODE;

/**
 * @author junnan
 */
@Slf4j
@Service
@ConditionalOnProperty(name = BaseConstant.APP + ".auth.enable", havingValue = "true")
public class LoginServiceImpl implements LoginApi {

    @Resource
    private SysConfService confService;

    @Resource
    private SysUserService userService;

    @Resource
    private SysDeptService deptService;

    @Resource
    private SysRoleService roleService;

    @Resource
    private SysMenuService menuService;

    @Resource
    private SysUserRoleService userRoleService;

    @Resource
    private SysRoleMenuService roleMenuService;

    @Resource
    private SysUserThirdService userThirdService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void checkCaptcha(String uuid, String captcha) {
        String captchaSwitch = confService.getValueByCode(AuthConstant.CONF_CAPTCHA_SWITCH);
        if (StrUtil.isBlank(captchaSwitch) || AuthConstant.CONF_CAPTCHA_SWITCH_DEFAULT
                .equalsIgnoreCase(captchaSwitch)) {
            return;
        }

        if (!StrUtil.isAllNotBlank(uuid, captcha)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_CAPTCHA_BLANK);
        }

        String captchaVal = stringRedisTemplate.opsForValue().get(CACHE_CAPTCHA_CODE + uuid);
        if (!captcha.equals(captchaVal)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_CAPTCHA_ERROR);
        }
    }

    @Override
    public LoginUserModel loadUserByName(String username) {
        return getSysUser(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
    }

    @Override
    public LoginUserModel loadUserByMobile(String mobile) {
        return getSysUser(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getMobile, mobile));
    }

    @Override
    public LoginUserModel loadUserByTpsUuid(String uuid) {
        SysUserThird userThird = userThirdService.getOne(Wrappers.<SysUserThird>lambdaQuery().eq(SysUserThird::getUuid, uuid));
        if (ObjectUtil.isNotNull(userThird)) {
            return getSysUser(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getId, userThird.getId()));
        }
        return null;
    }

    @Override
    public LoginUserModel wrapLoginUserPerm(LoginUserModel loginUserModel) {
        Integer userId = loginUserModel.getId();
        SysDept sysDept = deptService.getById(loginUserModel.getDeptId());
        if (ObjectUtil.isNotNull(sysDept)) {
            loginUserModel.setDeptName(sysDept.getName());
        }

        List<SysRole> roleList;
        List<SysMenu> menuList = new ArrayList<>();
        List<Integer> roleIdList = getRoleIdList(userId);
        if (CollUtil.isNotEmpty(roleIdList)) {
            loginUserModel.setRoleIdList(roleIdList);
            roleList = roleService.listByIds(roleIdList);
            loginUserModel.setRoleCodeList(roleList.stream().map(SysRole::getCode)
                    .filter(StrUtil::isNotBlank).collect(Collectors.toList()));

            List<Integer> menuIdList = getMenuIdList(roleIdList);
            loginUserModel.setMenuIdList(menuIdList);
            if (CollUtil.isNotEmpty(menuIdList)) {
                menuList = menuService.listByIds(menuIdList);
                loginUserModel.setMenuPermList(menuList.stream().map(SysMenu::getPerm)
                        .filter(StrUtil::isNotBlank).collect(Collectors.toList()));
            }
        }
        loginUserModel.setMenuPageJson(TreeHelper.buildMenuPageJson(menuList));
        return loginUserModel;
    }

    private List<Integer> getRoleIdList(Integer userId) {
        return userRoleService.list(Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getUserId, userId))
                .stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
    }

    private List<Integer> getMenuIdList(List<Integer> roleIdList) {
        return roleMenuService.list(Wrappers.<SysRoleMenu>lambdaQuery()
                .in(SysRoleMenu::getRoleId, roleIdList))
                .stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
    }

    private LoginUserModel getSysUser(LambdaQueryWrapper<SysUser> queryWrapper) {
        queryWrapper.eq(SysUser::getLokFlag, 0);
        SysUser sysUser = userService.getOne(queryWrapper);
        if (ObjectUtil.isNull(sysUser) || DelFlagEnum.Y.getValue().equals(sysUser.getDelFlag())) {
            throw new ServiceException(SysExceptionEnum.USER_NOT_EXIST);
        }
        return BeanUtil.copyProperties(sysUser, LoginUserModel.class);
    }

}
